{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1be69f0e-bc9c-41c1-ba7b-c5b9a42c2e7e",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "!pip install sentence-transformers -Uq"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "736dc101-5863-44ff-b086-a25a69f0b51d",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "!pip install datasets -q\n",
    "!pip install  accelerate -Uq\n",
    "!pip install tensorboard -q"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b59b9525-038f-4820-9d22-1de0d83bfbf7",
   "metadata": {},
   "source": [
    "# finetune 模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "9c2ae124-2a55-4713-afe0-c40be9b3bb5f",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from sentence_transformers import SentenceTransformer, LoggingHandler\n",
    "from datasets import load_dataset\n",
    "from sentence_transformers import InputExample\n",
    "from transformers import AutoTokenizer, AutoModel\n",
    "from torch.utils.data import DataLoader\n",
    "from sentence_transformers import losses\n",
    "import torch\n",
    "import logging"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "07bc65f6-c9a2-47bc-a2da-094b8924ca15",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "logging.basicConfig(format='%(asctime)s - %(message)s', datefmt = '%Y-%m-%d %H:%M:S', level=logging.INFO, handlers =[LoggingHandler()] )\n",
    "device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "2805f9cd-4a2a-420f-bfc9-f36d5d23de54",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import logging\n",
    "import os\n",
    "import csv\n",
    "import numpy as np\n",
    "from typing import List, Union\n",
    "import math\n",
    "from tqdm.autonotebook import trange\n",
    "from torch.utils.tensorboard import SummaryWriter\n",
    "import torch\n",
    "from torch import nn\n",
    "from sentence_transformers.util import batch_to_device\n",
    "from sentence_transformers.evaluation import SentenceEvaluator\n",
    "from sentence_transformers import InputExample\n",
    "\n",
    "logger = logging.getLogger(__name__)\n",
    "\n",
    "\n",
    "class LossEvaluator(SentenceEvaluator):\n",
    "\n",
    "    def __init__(self, loader, loss_model: nn.Module = None, name: str = '', log_dir: str = None,\n",
    "                 show_progress_bar: bool = False, write_csv: bool = True):\n",
    "\n",
    "        \"\"\"\n",
    "        Evaluate a model based on the loss function.\n",
    "        The returned score is loss value.\n",
    "        The results are written in a CSV and Tensorboard logs.\n",
    "        :param loader: Data loader object\n",
    "        :param loss_model: loss module object\n",
    "        :param name: Name for the output\n",
    "        :param log_dir: path for tensorboard logs \n",
    "        :param show_progress_bar: If true, prints a progress bar\n",
    "        :param write_csv: Write results to a CSV file\n",
    "        \"\"\"\n",
    "\n",
    "        self.loader = loader\n",
    "        self.write_csv = write_csv\n",
    "        self.logs_writer = SummaryWriter(log_dir=log_dir)\n",
    "        self.name = name\n",
    "        self.loss_model = loss_model\n",
    "\n",
    "        # move model to gpu:  lidija-jovanovska\n",
    "        self.device = torch.device(\"cuda\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "        loss_model.to(self.device)\n",
    "\n",
    "        if show_progress_bar is None:\n",
    "            show_progress_bar = (\n",
    "                    logger.getEffectiveLevel() == logging.INFO or logger.getEffectiveLevel() == logging.DEBUG)\n",
    "        self.show_progress_bar = show_progress_bar\n",
    "\n",
    "        self.csv_file = \"loss_evaluation\" + (\"_\" + name if name else '') + \"_results.csv\"\n",
    "        self.csv_headers = [\"epoch\", \"steps\", \"loss\"]\n",
    "\n",
    "    def __call__(self, model, output_path: str = None, epoch: int = -1, steps: int = -1) -> float:\n",
    "\n",
    "        self.loss_model.eval()\n",
    "\n",
    "        loss_value = 0\n",
    "        self.loader.collate_fn = model.smart_batching_collate\n",
    "        num_batches = len(self.loader)\n",
    "        data_iterator = iter(self.loader)\n",
    "\n",
    "        with torch.no_grad():\n",
    "            for _ in trange(num_batches, desc=\"Iteration\", smoothing=0.05, disable=not self.show_progress_bar):\n",
    "                sentence_features, labels = next(data_iterator)\n",
    "                #move data to GPU: lidija-jovanovska\n",
    "                sentence_features = list(map(lambda batch: batch_to_device(batch, self.device), sentence_features))\n",
    "                labels = labels.to(self.device)\n",
    "                loss_value += self.loss_model(sentence_features, labels).item()\n",
    "\n",
    "        final_loss = loss_value / num_batches\n",
    "        if output_path is not None and self.write_csv:\n",
    "\n",
    "            csv_path = os.path.join(output_path, self.csv_file)\n",
    "            output_file_exists = os.path.isfile(csv_path)\n",
    "\n",
    "            with open(csv_path, newline='', mode=\"a\" if output_file_exists else 'w', encoding=\"utf-8\") as f:\n",
    "                writer = csv.writer(f)\n",
    "                if not output_file_exists:\n",
    "                    writer.writerow(self.csv_headers)\n",
    "\n",
    "                writer.writerow([epoch, steps, final_loss])\n",
    "                logging.info(f'epoch:{epoch}, steps:{steps}, final_loss:{final_loss}')\n",
    "\n",
    "            #...log the running loss\n",
    "            self.logs_writer.add_scalar('val_loss',\n",
    "                                        final_loss,\n",
    "                                        steps)\n",
    "\n",
    "        self.loss_model.zero_grad()\n",
    "        self.loss_model.train()\n",
    "\n",
    "        return final_loss"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4e2e9e75-5fdf-4e85-967f-e4d86f85902a",
   "metadata": {},
   "source": [
    "## 从hf加载模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "66eade76-c737-4abc-8a2d-625347306f2c",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2023-09-14 08:26:S - Load pretrained SentenceTransformer: sentence-transformers/paraphrase-multilingual-mpnet-base-v2\n",
      "2023-09-14 08:27:S - Use pytorch device: cuda\n"
     ]
    }
   ],
   "source": [
    "model_location ='sentence-transformers/paraphrase-multilingual-mpnet-base-v2'\n",
    "# tokenizer = AutoTokenizer.from_pretrained(model_location)\n",
    "# model = AutoModel.from_pretrained(model_location).to(device) \n",
    "\n",
    "modelB = SentenceTransformer(model_location)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b354940c-7169-44d0-acf9-d03de31b679d",
   "metadata": {},
   "source": [
    "## Option 1 加载FAQ语料"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "fcfa89a5-e6af-45fa-9b76-7b05900aabbb",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import os,datasets\n",
    "# filenames = os.listdir('topwar_faq')\n",
    "filenames = ['cleaned_topwar_enrich_faq_0911.faq','topwarfaq230908.faq']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "5808a2dd-569a-4513-9ded-3c25b35a64c9",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "data size:5235\n"
     ]
    }
   ],
   "source": [
    "def parse_faq(file_content,QA_SEP='====='):\n",
    "    arr = file_content.split(QA_SEP)\n",
    "    list_arr = []\n",
    "    for item in arr:\n",
    "        question, answer = item.strip().split(\"\\n\", 1)\n",
    "        question = question.replace(\"Question: \", \"\")\n",
    "        answer = answer.replace(\"Answer: \", \"\")\n",
    "        list_arr.append((answer,question))\n",
    "    return list_arr\n",
    "\n",
    "all_datas = []\n",
    "for fn in filenames:\n",
    "    if fn == '.ipynb_checkpoints':\n",
    "        continue\n",
    "    with open(f\"docs/{fn}\") as f:\n",
    "        data = f.read()\n",
    "        all_datas += parse_faq(data)\n",
    "print(f\"data size:{len(all_datas)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "317a7961-d7e0-4e15-ba02-2277c7703b94",
   "metadata": {},
   "source": [
    "## Option 2 加载csv预料"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c4972088-96e8-4efb-81b0-6599a42b4eba",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# import pandas as pd\n",
    "# import re"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fb31d7b5-b235-448a-9e69-fed3ee6ba39f",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# df = pd.read_csv('docs/topwar_faq_new.csv')\n",
    "# df=df[['answer','question']].dropna()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a9c60d4f-088e-4965-86e8-8615c71cb22c",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# df['question'] = df['question'].map(lambda x: re.sub(r'^(\\d+.\\s?)','',x.strip()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5576fed1-a365-476b-93ae-d72d131e8ca6",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# #增加问题对标志\n",
    "\n",
    "# def convert_vocab_to_token_id(vocab, word):\n",
    "#     vocab_dict = {word: idx for idx, word in enumerate(vocab)}\n",
    "#     # token_ids = [vocab_dict.get(word, -1) for word in words]\n",
    "#     token_id = vocab_dict.get(word, -1)\n",
    "#     return token_id\n",
    "\n",
    "\n",
    "# vocab = list(set(df['answer']))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eb9e3457-c483-43af-a389-96b431ced5f9",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# df['idx'] = df['answer'].map(lambda x:convert_vocab_to_token_id(vocab,x)) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1fafb212-1900-4682-8b2a-96ea7c682908",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# all_datas=df[['answer','question']].values.tolist()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "70f271d3-1a2c-4c82-a69c-4c8bea89e6b8",
   "metadata": {},
   "source": [
    "## 准备dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "734c79a3-92b1-4740-909e-e7e195099bf6",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_examples = []\n",
    "\n",
    "for i in range(len(all_datas)):\n",
    "    example = all_datas[i]\n",
    "    train_examples.append(InputExample(texts=[example[0], example[1]]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "f3450840-b2a4-433a-8b26-22bbf2a5c94e",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "75fe0961-86e9-40db-ae4a-0880ac9437fb",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['高级招募券是一种可在游戏商店中购买高级兵种、加快招募速度的道具，是提升游戏实力的必备品之一。', '高级招募券可以用来做什么？']"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_examples[np.random.randint(1,len(train_examples))].texts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "95c874f8-1f0c-40d9-b9b3-6d4a219646fe",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_dataloader = DataLoader(train_examples, shuffle=True, batch_size=4)\n",
    "train_loss = losses.MultipleNegativesRankingLoss(model=modelB)\n",
    "num_epochs = 1\n",
    "warmup_steps = int(len(train_dataloader) * num_epochs * 0.1) #10% of train data\n",
    "dev_evaluator = LossEvaluator(train_dataloader, loss_model=train_loss, log_dir='logs/', name='dev')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7353170e-a8af-494b-8981-40f586446955",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "8cfacc864e8e443ca0401d14bb9e32ba",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Epoch:   0%|          | 0/1 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "3f7ed7d133784d40a9955307f609c038",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Iteration:   0%|          | 0/1309 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2023-09-14 08:32:S - epoch:0, steps:10, final_loss:0.22323689285785928\n",
      "2023-09-14 08:32:S - Save model to ./finetuned-sentence-embedding\n",
      "2023-09-14 08:33:S - epoch:0, steps:20, final_loss:0.20777995802925261\n",
      "2023-09-14 08:34:S - epoch:0, steps:30, final_loss:0.18431827710114468\n",
      "2023-09-14 08:34:S - epoch:0, steps:40, final_loss:0.16595870878371619\n",
      "2023-09-14 08:35:S - epoch:0, steps:50, final_loss:0.14521464054692604\n",
      "2023-09-14 08:35:S - epoch:0, steps:60, final_loss:0.11465142419169568\n",
      "2023-09-14 08:36:S - epoch:0, steps:70, final_loss:0.11630305185804295\n"
     ]
    }
   ],
   "source": [
    "torch.cuda.empty_cache()\n",
    "modelB.fit(train_objectives=[(train_dataloader, train_loss)],\n",
    "          epochs=num_epochs,\n",
    "           evaluator=dev_evaluator,\n",
    "            evaluation_steps=10,\n",
    "           output_path='./finetuned-sentence-embedding',\n",
    "          warmup_steps=warmup_steps)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d4597bff-501a-47e0-83df-a4a672823f18",
   "metadata": {
    "tags": []
   },
   "source": [
    "## 从本地加载finetuned的模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "18fd2552-4321-4c94-8452-2177b731554b",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# modelB = SentenceTransformer('./finetuned-sentence-embedding')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b22cf8b3-ee0b-4032-a190-56cc556bb905",
   "metadata": {},
   "source": [
    "## 抽样"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6bfdd412-09e1-43d7-966a-a6d40beefdb7",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from sentence_transformers import evaluation,util\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6b3c7f69-dde3-4534-9338-5bdc326688d3",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "df = pd.DataFrame(all_datas,columns=['answer','question'])\n",
    "df"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d7bfd06d-7831-4b67-959a-6dc0298a45ee",
   "metadata": {},
   "source": [
    "## 抽样20%数据拿出来算距离"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "da806252-894d-4ef5-b893-9c74c9e46dd6",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "### 抽取一部分，做交叉负样本\n",
    "# sample_size = int(len(all_datas)*0.2)\n",
    "# df_sample_1 = df.sample(sample_size)\n",
    "# df_sample_2 = df.sample(sample_size)\n",
    "\n",
    "# ##去除sample1 和 sample 2中的重复部分\n",
    "# df_dup_sample = df_sample_1.join(df_sample_2,rsuffix='_r')\n",
    "# df_dup_sample = df_dup_sample[~df_dup_sample.question_r.isna()][['question','answer']]\n",
    "\n",
    "# df_sample_1_dedup = df_sample_1.join(df_dup_sample,how='left',rsuffix ='_r')\n",
    "# df_sample_1_dedup = df_sample_1_dedup[df_sample_1_dedup.question_r.isna()]\n",
    "\n",
    "# df_sample_2_dedup = df_sample_2.join(df_dup_sample,how='left',rsuffix='_r')\n",
    "# df_sample_2_dedup = df_sample_2_dedup[df_sample_2_dedup.question_r.isna()]\n",
    "\n",
    "\n",
    "# #将sample 1 的答案和sample 2 的问题组成负样本\n",
    "# input_answer  = []\n",
    "# input_question  = []\n",
    "# for a,b in zip(df_sample_1_dedup.answer,df_sample_2_dedup.question):\n",
    "#     input_answer.append(a)\n",
    "#     input_question.append(b)\n",
    "# print(f'negative sample size:{df_sample_2_dedup.shape[0]}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cb77deba-a613-4177-bf04-7f02692614d5",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# emb_answer = modelB.encode(input_answer)\n",
    "# emb_question = modelB.encode(input_question)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "807f79e8-002a-4f86-9294-27b11158cbb3",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "input_answer  = []\n",
    "input_question  = []\n",
    "sample_size = int(len(all_datas)*0.2)\n",
    "df_sample = df.sample(sample_size)\n",
    "for a,b in zip(df_sample.answer,df_sample.question):\n",
    "    input_answer.append(a)\n",
    "    input_question.append(b)\n",
    "print(f'sample size:{df_sample.shape[0]}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a9bbeb9d-7d2d-4e47-aa4c-3cacb31db498",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "emb_answer = modelB.encode(input_answer)\n",
    "emb_question = modelB.encode(input_question)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b8715caf-e85a-4690-beb2-0d732a8b244d",
   "metadata": {
    "tags": []
   },
   "source": [
    "## 将question和answer进行cross 对比，查看这个分布。\n",
    "### 输出矩阵的对角线的结果代表的是正样本，其他非对角线的则是交叉样本（负样本）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e529a082-e4d0-4f0e-85bd-f38160a09cfb",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 计算所有q和a之间的相似度\n",
    "cross_simsvalues = util.cos_sim(emb_answer,emb_question).flatten()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "23cfc0f1-4468-48bb-8349-1011605d5870",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "cross_sims_s = pd.Series(cross_simsvalues)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cdd17e5a-01cc-481b-9f36-e56944f2cd86",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "N = len(input_question)\n",
    "pos_indices = [ i*N+i for i in range(N)] ##只取出正例的index"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "92f376bf-da76-4f80-bf93-ca0165f2dbbf",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 正样本的得分\n",
    "pos_cross_sims_s = cross_sims_s[pos_indices]\n",
    "pos_cross_sims_s.describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a1b58af3-47be-423a-8999-da07609eaa9f",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "##去除对角线上的元素\n",
    "neg_cross_sims_s = cross_sims_s.drop(pos_indices)\n",
    "neg_cross_sims_s.describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "98bfbea3-1274-4ea0-91d9-69af1784600c",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import seaborn as sns\n",
    "sns.histplot(pos_cross_sims_s, color='green',kde=True)\n",
    " ##负样本较多，只采样一部分进行plot\n",
    "sns.histplot(neg_cross_sims_s.sample(len(pos_cross_sims_s)), color='red',kde=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a9b8002-1cb8-4899-a903-c43fabf37ddc",
   "metadata": {},
   "source": [
    "## 输出具体的结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7f5224be-74af-410b-b165-e211399bc26b",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "def similarity(v1,v2):\n",
    "    dot_product = np.dot(v1, v2)\n",
    "\n",
    "    magnitude_v1 = np.linalg.norm(v1)\n",
    "    magnitude_v2 = np.linalg.norm(v2)\n",
    "\n",
    "    return dot_product / (magnitude_v1 * magnitude_v2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "833ee658-32b0-49ab-b6eb-2c9b258e1762",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "for i in range(len(input_question)):\n",
    "    sims = similarity(emb_answer[i],emb_question[i])\n",
    "    print(f\"Question:{input_question[i]}\\nAnswer:{input_answer[i]}\\n{sims}\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cd63deec-e324-470e-aad4-ff13cabcbaba",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "348b3ab6-f42d-4c54-a9b7-3a6223387168",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "input_queries = ['雷电将军好不好使？']\n",
    "q_embedding = modelB.encode(input_queries)\n",
    "results = util.semantic_search(query_embeddings = q_embedding,corpus_embeddings= emb_question,top_k=3)\n",
    "results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6b7015ab-0ab1-4b5a-bb70-1f1eff19c8cf",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "for ret in results[0]:\n",
    "    print(f\"{all_datas[ret['corpus_id']]} score:{ret['score']}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ec80db02-8714-4132-8457-2acf024b1a59",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "2d47bd28-2482-47cb-b058-9f2f8bce9944",
   "metadata": {},
   "source": [
    "# 使用pre trained 模型对比"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1b06da68-f9ef-46a6-8665-a2369c9a012b",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "modelA = SentenceTransformer('sentence-transformers/paraphrase-multilingual-mpnet-base-v2')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "51f4ecb2-24f9-4847-846d-87aba754e7cd",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "emb_answer_2 = modelA.encode(input_answer)\n",
    "emb_question_2 = modelA.encode(input_question)\n",
    "cross_simsvalues_2 = util.cos_sim(emb_answer_2,emb_question_2).flatten()\n",
    "cross_sims_s_2 = pd.Series(cross_simsvalues_2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e45be0c2-9635-49a4-a8e8-6c9699b69551",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "len(emb_answer)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9c7a6222-8789-4196-abd2-960694850082",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "#负样本得分\n",
    "N = len(input_question)\n",
    "pos_indices = [ i*N+i for i in range(N)] \n",
    "neg_cross_sims_s_2 = cross_sims_s_2.drop(pos_indices)\n",
    "neg_cross_sims_s_2.describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d2814786-c424-43a0-81ef-184b6a0e432c",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 正样本的得分\n",
    "pos_cross_sims_s_2 = cross_sims_s_2[pos_indices]\n",
    "pos_cross_sims_s_2.describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "24c8a709-d438-42c9-937b-5cb7e89d3137",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import seaborn as sns\n",
    "sns.histplot(pos_cross_sims_s_2, color='green',kde=True)\n",
    " ##负样本较多，只采样一部分进行plot\n",
    "sns.histplot(neg_cross_sims_s_2.sample(N), color='red',kde=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a7cc99a0-ee6a-4902-b8af-b7c6cc9da18a",
   "metadata": {},
   "source": [
    "# 部署模型到sagemaker"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "57dc4832-b17a-47b0-8662-4ced85f29952",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "!pip install --upgrade pip -q\n",
    "!pip install -U sagemaker -q"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b0490240-edff-4fff-8eec-bd295bf43f99",
   "metadata": {},
   "source": [
    "## 2. 把模型拷贝到S3为后续部署做准备"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "df4a6f16-63af-4c84-9dda-0af0dfa7b487",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import sagemaker\n",
    "from sagemaker import image_uris\n",
    "import boto3\n",
    "import os\n",
    "import time\n",
    "import json\n",
    "\n",
    "role = sagemaker.get_execution_role()  # execution role for the endpoint\n",
    "sess = sagemaker.session.Session()  # sagemaker session for interacting with different AWS APIs\n",
    "bucket = sess.default_bucket()  # bucket to house artifacts\n",
    "\n",
    "region = sess._region_name\n",
    "account_id = sess.account_id()\n",
    "\n",
    "s3_client = boto3.client(\"s3\")\n",
    "sm_client = boto3.client(\"sagemaker\")\n",
    "smr_client = boto3.client(\"sagemaker-runtime\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2fb24429-b2e5-4259-bd2d-70aa006c8cd1",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "s3_model_prefix = \"LLM-RAG/workshop/finetuned-sentence2emb-model\"  # folder where model checkpoint will go\n",
    "model_snapshot_path = \"./finetuned-sentence-embedding\"\n",
    "s3_code_prefix = \"LLM-RAG/workshop/finetuned-sentence2emb_deploy_code\"\n",
    "print(f\"s3_code_prefix: {s3_code_prefix}\")\n",
    "print(f\"model_snapshot_path: {model_snapshot_path}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e53e83fd-305a-42f8-83cf-e0a17779eaac",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "!aws s3 cp --recursive {model_snapshot_path} s3://{bucket}/{s3_model_prefix}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e227e0f2-afb3-4d1f-b484-bcb6b77e3a4b",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "!pip install -U sagemaker -q"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4e4c4651-d731-4e8d-8deb-350918d8d721",
   "metadata": {},
   "source": [
    "### 3. 模型部署准备（entrypoint脚本，容器镜像，服务配置）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8a07ff35-d547-4df3-b511-4be2862dcb6e",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# China Region\n",
    "# inference_image_uri = (\n",
    "#     f\"763104351884.dkr.ecr.{region}.amazonaws.com/djl-inference:0.21.0-deepspeed0.8.3-cu117\"\n",
    "# )\n",
    "\n",
    "inference_image_uri = image_uris.retrieve(\n",
    "    framework=\"djl-deepspeed\",\n",
    "    region=sess.boto_session.region_name,\n",
    "    version=\"0.23.0\"\n",
    ")\n",
    "print(f\"Image going to be used is ---- > {inference_image_uri}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4858bfe1-0392-41fd-8c46-d4a04a520397",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "!mkdir -p sentence2emb_deploy_code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5fe26158-4b50-4659-a869-6d64f3d152e4",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "%%writefile sentence2emb_deploy_code/model.py\n",
    "from djl_python import Input, Output\n",
    "import torch\n",
    "import logging\n",
    "import math\n",
    "import os\n",
    "from sentence_transformers import SentenceTransformer\n",
    "\n",
    "\n",
    "def load_model(properties):\n",
    "    tensor_parallel = properties[\"tensor_parallel_degree\"]\n",
    "    model_location = properties['model_dir']\n",
    "    if \"model_id\" in properties:\n",
    "        model_location = properties['model_id']\n",
    "    logging.info(f\"Loading model in {model_location}\")\n",
    "\n",
    "    # model =  FlagModel(model_location)\n",
    "    model = SentenceTransformer(model_location)\n",
    "    \n",
    "    return model\n",
    "\n",
    "model = None\n",
    "\n",
    "def handle(inputs: Input):\n",
    "    global model\n",
    "    if not model:\n",
    "        model = load_model(inputs.get_properties())\n",
    "\n",
    "    if inputs.is_empty():\n",
    "        return None\n",
    "    data = inputs.get_as_json()\n",
    "    \n",
    "    input_sentences = None\n",
    "    inputs = data[\"inputs\"]\n",
    "    if isinstance(inputs, list):\n",
    "        input_sentences = inputs\n",
    "    else:\n",
    "        input_sentences =  [inputs]\n",
    "        \n",
    "    logging.info(f\"inputs: {input_sentences}\")\n",
    "\n",
    "    sentence_embeddings =  model.encode(input_sentences,normalize_embeddings=True)\n",
    "        \n",
    "    result = {\"sentence_embeddings\": sentence_embeddings}\n",
    "    return Output().add_as_json(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d5c02fa9-d046-42a7-88fc-fc81fe890313",
   "metadata": {},
   "source": [
    "#### Note: option.s3url 需要按照自己的账号进行修改"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "64254ec0-69ab-4c2f-a9bb-05f259ab5218",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "%%writefile sentence2emb_deploy_code/serving.properties\n",
    "engine=Python\n",
    "option.tensor_parallel_degree=1\n",
    "option.s3url = s3://sagemaker-us-east-2-946277762357/LLM-RAG/workshop/finetuned-sentence2emb-model/"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9a466689-53df-4ba1-85de-f9fccaa151c4",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "%%writefile sentence2emb_deploy_code/requirements.txt\n",
    "transformers==4.30.2\n",
    "sentence-transformers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d76dad38-02f0-46f9-9121-9cb5155d7a76",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "!rm s2e_model.tar.gz\n",
    "!cd sentence2emb_deploy_code && rm -rf \".ipynb_checkpoints\"\n",
    "!tar czvf s2e_model.tar.gz sentence2emb_deploy_code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "76d3d300-4d4d-4ea3-a7d8-2667619cd727",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "s3_code_artifact = sess.upload_data(\"s2e_model.tar.gz\", bucket, s3_code_prefix)\n",
    "print(f\"S3 Code or Model tar ball uploaded to --- > {s3_code_artifact}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dc1a07e1-0955-497f-ba2d-9991a6deb833",
   "metadata": {},
   "source": [
    "### 4. 创建模型 & 创建endpoint"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b9318f47-36c1-4f16-962b-bdfe84c77c16",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from sagemaker.utils import name_from_base\n",
    "import boto3\n",
    "\n",
    "model_name = name_from_base(\"finetuned-mpnet\") #Note: Need to specify model_name\n",
    "print(model_name)\n",
    "print(f\"Image going to be used is ---- > {inference_image_uri}\")\n",
    "\n",
    "create_model_response = sm_client.create_model(\n",
    "    ModelName=model_name,\n",
    "    ExecutionRoleArn=role,\n",
    "    PrimaryContainer={\n",
    "        \"Image\": inference_image_uri,\n",
    "        \"ModelDataUrl\": s3_code_artifact\n",
    "    },\n",
    "    \n",
    ")\n",
    "model_arn = create_model_response[\"ModelArn\"]\n",
    "\n",
    "print(f\"Created Model: {model_arn}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9a7a2371-de79-4240-b029-80c15a674a7f",
   "metadata": {},
   "source": [
    "###  如果批量创建索引量较多，建议改成\"InstanceType\": \"ml.g4dn.xlarge\","
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e337d531-3324-4ae4-ac76-66c3418fd548",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "endpoint_config_name = f\"{model_name}-config\"\n",
    "endpoint_name = f\"{model_name}-endpoint\"\n",
    "\n",
    "endpoint_config_response = sm_client.create_endpoint_config(\n",
    "    EndpointConfigName=endpoint_config_name,\n",
    "    ProductionVariants=[\n",
    "        {\n",
    "            \"VariantName\": \"variant1\",\n",
    "            \"ModelName\": model_name,\n",
    "            \"InstanceType\": \"ml.g4dn.xlarge\",\n",
    "            \"InitialInstanceCount\": 1,\n",
    "            # \"VolumeSizeInGB\" : 400,\n",
    "            # \"ModelDataDownloadTimeoutInSeconds\": 2400,\n",
    "            \"ContainerStartupHealthCheckTimeoutInSeconds\": 10*60,\n",
    "        },\n",
    "    ],\n",
    ")\n",
    "endpoint_config_response"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "75f6a4b6-c36a-4ec5-8dd9-35b237ba55ba",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "create_endpoint_response = sm_client.create_endpoint(\n",
    "    EndpointName=f\"{endpoint_name}\", EndpointConfigName=endpoint_config_name\n",
    ")\n",
    "print(f\"Created Endpoint: {create_endpoint_response['EndpointArn']}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "277cc50a-d67e-4d01-ae58-18af86bf6259",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import time\n",
    "\n",
    "resp = sm_client.describe_endpoint(EndpointName=endpoint_name)\n",
    "status = resp[\"EndpointStatus\"]\n",
    "print(\"Status: \" + status)\n",
    "\n",
    "while status == \"Creating\":\n",
    "    time.sleep(60)\n",
    "    resp = sm_client.describe_endpoint(EndpointName=endpoint_name)\n",
    "    status = resp[\"EndpointStatus\"]\n",
    "    print(\"Status: \" + status)\n",
    "\n",
    "print(\"Arn: \" + resp[\"EndpointArn\"])\n",
    "print(\"Status: \" + status)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ef9ac01c-e8d9-4887-be4e-baded6d36abc",
   "metadata": {},
   "source": [
    "## 5. 模型测试"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1bef7a45-2484-4c77-8b14-1f6d5fea6b01",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def get_vector_by_sm_endpoint(questions, sm_client, endpoint_name):\n",
    "    # parameters = {\n",
    "    #     \"max_new_tokens\": 50,\n",
    "    #     \"temperature\": 0,\n",
    "    #     \"min_length\": 10,\n",
    "    #     \"no_repeat_ngram_size\": 2,\n",
    "    # }\n",
    "\n",
    "    response_model = sm_client.invoke_endpoint(\n",
    "        EndpointName=endpoint_name,\n",
    "        Body=json.dumps(\n",
    "            {\n",
    "                \"inputs\": questions,\n",
    "                # \"parameters\": parameters\n",
    "            }\n",
    "        ),\n",
    "        ContentType=\"application/json\",\n",
    "    )\n",
    "    json_str = response_model['Body'].read().decode('utf8')\n",
    "    json_obj = json.loads(json_str)\n",
    "    embeddings = json_obj['sentence_embeddings']\n",
    "    return embeddings"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "61b0cb25-1e16-4a70-a77c-f5e644d1166e",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "prompts1 = \"\"\"专属技能碎片在哪里获得？\"\"\"\n",
    "prompts1 = \"\"\"中国首都在哪里？\"\"\"\n",
    "\n",
    "emb1 = get_vector_by_sm_endpoint(prompts1, smr_client, endpoint_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2f37256a-7fa3-4e4c-b0c5-f17e0e8f858a",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "prompts2 = \"\"\"专属技能碎片可以通过多种途径获得，例如礼包商城-特惠礼包界面可以购买专属技能碎片礼包\"\"\"\n",
    "emb2 = get_vector_by_sm_endpoint(prompts2, smr_client, endpoint_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9377d20d-31c8-493e-9247-135052e35cbb",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "util.cos_sim(emb1,emb2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4f3a2f25-e206-439e-b8ee-b5f4216f09a9",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "availableInstances": [
   {
    "_defaultOrder": 0,
    "_isFastLaunch": true,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 4,
    "name": "ml.t3.medium",
    "vcpuNum": 2
   },
   {
    "_defaultOrder": 1,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 8,
    "name": "ml.t3.large",
    "vcpuNum": 2
   },
   {
    "_defaultOrder": 2,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.t3.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 3,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.t3.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 4,
    "_isFastLaunch": true,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 8,
    "name": "ml.m5.large",
    "vcpuNum": 2
   },
   {
    "_defaultOrder": 5,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.m5.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 6,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.m5.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 7,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 64,
    "name": "ml.m5.4xlarge",
    "vcpuNum": 16
   },
   {
    "_defaultOrder": 8,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 128,
    "name": "ml.m5.8xlarge",
    "vcpuNum": 32
   },
   {
    "_defaultOrder": 9,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 192,
    "name": "ml.m5.12xlarge",
    "vcpuNum": 48
   },
   {
    "_defaultOrder": 10,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 256,
    "name": "ml.m5.16xlarge",
    "vcpuNum": 64
   },
   {
    "_defaultOrder": 11,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 384,
    "name": "ml.m5.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 12,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 8,
    "name": "ml.m5d.large",
    "vcpuNum": 2
   },
   {
    "_defaultOrder": 13,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.m5d.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 14,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.m5d.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 15,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 64,
    "name": "ml.m5d.4xlarge",
    "vcpuNum": 16
   },
   {
    "_defaultOrder": 16,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 128,
    "name": "ml.m5d.8xlarge",
    "vcpuNum": 32
   },
   {
    "_defaultOrder": 17,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 192,
    "name": "ml.m5d.12xlarge",
    "vcpuNum": 48
   },
   {
    "_defaultOrder": 18,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 256,
    "name": "ml.m5d.16xlarge",
    "vcpuNum": 64
   },
   {
    "_defaultOrder": 19,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 384,
    "name": "ml.m5d.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 20,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": true,
    "memoryGiB": 0,
    "name": "ml.geospatial.interactive",
    "supportedImageNames": [
     "sagemaker-geospatial-v1-0"
    ],
    "vcpuNum": 0
   },
   {
    "_defaultOrder": 21,
    "_isFastLaunch": true,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 4,
    "name": "ml.c5.large",
    "vcpuNum": 2
   },
   {
    "_defaultOrder": 22,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 8,
    "name": "ml.c5.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 23,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.c5.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 24,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.c5.4xlarge",
    "vcpuNum": 16
   },
   {
    "_defaultOrder": 25,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 72,
    "name": "ml.c5.9xlarge",
    "vcpuNum": 36
   },
   {
    "_defaultOrder": 26,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 96,
    "name": "ml.c5.12xlarge",
    "vcpuNum": 48
   },
   {
    "_defaultOrder": 27,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 144,
    "name": "ml.c5.18xlarge",
    "vcpuNum": 72
   },
   {
    "_defaultOrder": 28,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 192,
    "name": "ml.c5.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 29,
    "_isFastLaunch": true,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.g4dn.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 30,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.g4dn.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 31,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 64,
    "name": "ml.g4dn.4xlarge",
    "vcpuNum": 16
   },
   {
    "_defaultOrder": 32,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 128,
    "name": "ml.g4dn.8xlarge",
    "vcpuNum": 32
   },
   {
    "_defaultOrder": 33,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 4,
    "hideHardwareSpecs": false,
    "memoryGiB": 192,
    "name": "ml.g4dn.12xlarge",
    "vcpuNum": 48
   },
   {
    "_defaultOrder": 34,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 256,
    "name": "ml.g4dn.16xlarge",
    "vcpuNum": 64
   },
   {
    "_defaultOrder": 35,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 61,
    "name": "ml.p3.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 36,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 4,
    "hideHardwareSpecs": false,
    "memoryGiB": 244,
    "name": "ml.p3.8xlarge",
    "vcpuNum": 32
   },
   {
    "_defaultOrder": 37,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 8,
    "hideHardwareSpecs": false,
    "memoryGiB": 488,
    "name": "ml.p3.16xlarge",
    "vcpuNum": 64
   },
   {
    "_defaultOrder": 38,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 8,
    "hideHardwareSpecs": false,
    "memoryGiB": 768,
    "name": "ml.p3dn.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 39,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.r5.large",
    "vcpuNum": 2
   },
   {
    "_defaultOrder": 40,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.r5.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 41,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 64,
    "name": "ml.r5.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 42,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 128,
    "name": "ml.r5.4xlarge",
    "vcpuNum": 16
   },
   {
    "_defaultOrder": 43,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 256,
    "name": "ml.r5.8xlarge",
    "vcpuNum": 32
   },
   {
    "_defaultOrder": 44,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 384,
    "name": "ml.r5.12xlarge",
    "vcpuNum": 48
   },
   {
    "_defaultOrder": 45,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 512,
    "name": "ml.r5.16xlarge",
    "vcpuNum": 64
   },
   {
    "_defaultOrder": 46,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 768,
    "name": "ml.r5.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 47,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.g5.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 48,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.g5.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 49,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 64,
    "name": "ml.g5.4xlarge",
    "vcpuNum": 16
   },
   {
    "_defaultOrder": 50,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 128,
    "name": "ml.g5.8xlarge",
    "vcpuNum": 32
   },
   {
    "_defaultOrder": 51,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 256,
    "name": "ml.g5.16xlarge",
    "vcpuNum": 64
   },
   {
    "_defaultOrder": 52,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 4,
    "hideHardwareSpecs": false,
    "memoryGiB": 192,
    "name": "ml.g5.12xlarge",
    "vcpuNum": 48
   },
   {
    "_defaultOrder": 53,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 4,
    "hideHardwareSpecs": false,
    "memoryGiB": 384,
    "name": "ml.g5.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 54,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 8,
    "hideHardwareSpecs": false,
    "memoryGiB": 768,
    "name": "ml.g5.48xlarge",
    "vcpuNum": 192
   },
   {
    "_defaultOrder": 55,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 8,
    "hideHardwareSpecs": false,
    "memoryGiB": 1152,
    "name": "ml.p4d.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 56,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 8,
    "hideHardwareSpecs": false,
    "memoryGiB": 1152,
    "name": "ml.p4de.24xlarge",
    "vcpuNum": 96
   }
  ],
  "instance_type": "ml.g4dn.xlarge",
  "kernelspec": {
   "display_name": "Python 3 (PyTorch 2.0.0 Python 3.10 GPU Optimized)",
   "language": "python",
   "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-east-2:429704687514:image/pytorch-2.0.0-gpu-py310"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
